﻿using System;
using System.Web;
using System.Net;
using System.Threading.Tasks;
using System.Text;
using SimpleJSON;
using System.Collections.Generic;
using System.Threading.Tasks.Dataflow;

namespace TestHttp
{
	public class ClientActor : Actor
	{
		public readonly BufferBlock<bool> signal = new BufferBlock<bool>();
		public ClientActor()
		{
			Console.WriteLine("InitClientActor");
		}

		public async Task<string> Handle(HttpListenerContext context, ServerActor server)
		{

			Console.WriteLine("clientHandle: " );
			await this._messageQueue;
			var req = context.Request;
			var r = req.RawUrl.Split('?');
			string ret;
			//send?msg
			if (r[0] == "/send")
			{
				await server.AddMessage(r[1]);
				ret = "Suc";
			}
			//receive?id
			else if (r[0] == "/receive")
			{
				var id = Convert.ToInt32(r[1]);
				var msg = await server.GetMessage(id, this);
				var js = new JSONArray();
				foreach (var m in msg)
				{
					var jarr = new JSONArray();
					jarr.Add(m.msg);
					jarr.Add(new JSONData(m.id));

					js.Add(jarr);
				}
				ret = js.ToString();
			}
			else {
				ret = "Error";
			}
			//Console.WriteLine(r[0]);
			return ret;
		}
	}

	public class Message
	{
		public string msg;
		public int id;
	}
	public class ServerActor : Actor
	{
		private int maxId = 0;
		private List<Message> messageQueue = new List<Message>();

		private HttpListener httpListener;

		private List<ClientActor> clients = new List<ClientActor>();

		public Task<Task> task;
		public override void Init()
		{
			task = RunTask(RunHttp);
		}
		private async Task RunHttp()
		{
			var httpPort = 9090;
			httpListener = new HttpListener();
			httpListener.Prefixes.Add("http://*:" + httpPort + "/");
			httpListener.Start();
			while (httpListener.IsListening)
			{
				var context = await httpListener.GetContextAsync();
				var req = context.Request;
				Handle(context, req);
			}

			httpListener.Stop();
			httpListener.Close();
		}

		public async Task AddMessage(string msg)
		{
			await this._messageQueue;
			var m = new Message()
			{
				msg = msg,
				id = maxId++,
			};
			messageQueue.Add(m);

			foreach (var c in clients)
			{
				c.signal.SendAsync(true);
			}
		}

		public async Task<List<Message>> GetMessage(int id, ClientActor client)
		{
			await this._messageQueue;
			while (true)
			{
				Console.WriteLine("MaxId, Id:"+maxId+":"+id);
				if (id < maxId)
				{
					var ret = new List<Message>();
					foreach (var m in messageQueue)
					{
						if (m.id >= id)
						{
							ret.Add(m);
						}
					}
					if (ret.Count > 0)
					{
						clients.Remove(client);
						return ret;
					}
				}
				clients.Add(client);
				await client.signal.ReceiveAsync();
			}

		}

 		private async Task Handle(HttpListenerContext context, HttpListenerRequest req)
		{
			Console.WriteLine("RawURL: "+req.RawUrl);

			Console.WriteLine("ConstructClient");
			var client = new ClientActor();
			ActorManager.Instance.AddActor(client);
			Console.WriteLine("Beforehandle: ");
			var resp = await client.Handle(context, this);
			Console.WriteLine(resp);

			ActorManager.Instance.RemoveActor(client.Id);

			var buf = Encoding.UTF8.GetBytes(resp);
			context.Response.AddHeader("Content-Encoding", "utf-8");
			context.Response.ContentEncoding = Encoding.UTF8;
			context.Response.ContentLength64 = buf.Length;
			try
			{
				context.Response.OutputStream.Write(buf, 0, buf.Length);
			}
			catch (Exception exp)
			{
				Console.WriteLine(exp.ToString());
			}
			finally
			{
				context.Response.OutputStream.Close();
			}
		}
	}

	public class HttpServer
	{
		public Task task;
		private ActorManager actorManager;
		public HttpServer()
		{
			actorManager = new ActorManager();
			var serverActor = new ServerActor();
			actorManager.AddActor(serverActor);
			task = serverActor.task.Result;
		}

	}
}
